package com.ktg.mes.util;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.ktg.common.utils.DateUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

public class LGLeftJoinQueryWrapper<T>{

    private Map<String,Object> thisMap;

    // map key支持 between 之间
    private final static String keyStartFx = "_start";
    private final static String keyEndFx = "_end";

    private String leftJoinString = "";
    private Integer pageIndex;
    private Integer pageSize;
    private QueryModel queryModel = new QueryModel();

    private String defaultDateFormat = null;


    /**
     *  map key支持 like 右边模糊查询, 查询格式：'ss%' , 模糊查询字段之间用英文逗号分割：,
     *  如：{
     *      "lgQueryLikeRight":"device_name,record_id"
     *  }
      */
    private final static String keyLikeRightString = "lg_query_like_right"; //同时支持大小写：lg_query_like_right 和 lgQueryLikeRight


    /**
     *  map key支持 日期 查询精确到：年,月,日,小时,分钟，模糊查询字段之间用英文逗号分割：,
     *  如：{
     *      "lgDateHourString":"create_time,update_time"
     *  }
     */
    private final static String keyDateMinuteString = "lg_date_minute_string"; //同时支持大小写：lg_date_minute_string 和 lgDateMinuteString
    private final static String keyDateHourString = "lg_date_hour_string"; //同时支持大小写：lg_date_hour_string 和 lgDateHourString
    private final static String keyDateDayString = "lg_date_day_string"; //同时支持大小写：lg_date_day_string 和 lgDateDayString
    private final static String keyDateMonthString = "lg_date_month_string"; //同时支持大小写：lg_date_month_string 和 lgDateMonthString
    private final static String keyDateYearString = "lg_date_year_string"; //同时支持大小写：lg_date_year_string 和 lgDateYearString
    private String[] thisLikeRightStringList;

    private String[] thisDateMinuteStringList;
    private String[] thisDateHourStringList;

    private String[] thisDateDayStringList;
    private String[] thisDateMonthStringList;
    private String[] thisDateYearStringList;


    /**
     * 简单的left join 链表查询，支持 查询left join 链表中的字段查询，
     * 1、在model 中 使用@LeftJoin 来配置链表
     * 2、在model 中 @TableField(exist = false) 也能用于查询left join链表的字段，但不用于查询当前表的字段
     * @param object
     * @param httpServletRequestParameterMap
     */
    public LGLeftJoinQueryWrapper(Object object, Map httpServletRequestParameterMap){
        dealStart(object,httpServletRequestParameterMap,0,0);
    }
    /**
     * 简单的left join 链表查询，支持 查询left join 链表中的字段查询，
     * 1、在model 中 使用@LeftJoin 来配置链表
     * 2、在model 中 @TableField(exist = false) 也能用于查询left join链表的字段，但不用于查询当前表的字段
     * @param object
     * @param page
     * @param size
     * @param httpServletRequestParameterMap
     */
    public  LGLeftJoinQueryWrapper(Object object, Map httpServletRequestParameterMap,Integer page,Integer size){
        dealStart(object,httpServletRequestParameterMap,page,size);
    }


    /**
     * 简单的left join 链表查询，支持 查询left join 链表中的字段查询，
     * 1、在model 中 使用@LeftJoin 来配置链表
     * 2、在model 中 @TableField(exist = false) 也能用于查询left join链表的字段，但不用于查询当前表的字段
     * @param object
     * @param httpServletRequestParameterMap
     * @param page
     * @param size
     */
    public void dealStart(Object object, Map httpServletRequestParameterMap,Integer page,Integer size){
        Map map = httpServletRequestParameterMap;
        thisMap = new HashMap<>();
        pageIndex = page;
        pageSize = size;
        if (map != null){
            Set<String> keySet = map.keySet();
            for (String key:keySet) {
                thisMap.put(camelToUnderline(key),map.get(key));
            }
        }

        // like String
        if (thisMap.get(keyLikeRightString) != null){
            String str = null;
            if (thisMap.get(keyLikeRightString) instanceof String){
                str = (String) thisMap.get(keyLikeRightString);
            }else {
                str = ((String[]) thisMap.get(keyLikeRightString))[0];
            }
            thisLikeRightStringList = str.split(",");
        }

        // 按分钟查询
        if (thisMap.get(keyDateMinuteString) != null){
            String str = null;
            if (thisMap.get(keyDateMinuteString) instanceof String){
                str = (String) thisMap.get(keyDateMinuteString);
            }else {
                str = ((String[]) thisMap.get(keyDateMinuteString))[0];
            }
            thisDateMinuteStringList = str.split(",");
        }

        // 按小时查询
        if (thisMap.get(keyDateHourString) != null){
            String str = null;
            if (thisMap.get(keyDateHourString) instanceof String){
                str = (String) thisMap.get(keyDateHourString);
            }else {
                str = ((String[]) thisMap.get(keyDateHourString))[0];
            }
            thisDateHourStringList = str.split(",");
        }

        // 按天查询
        if (thisMap.get(keyDateDayString) != null){
            String str = null;
            if (thisMap.get(keyDateDayString) instanceof String){
                str = (String) thisMap.get(keyDateDayString);
            }else {
                str = ((String[]) thisMap.get(keyDateDayString))[0];
            }
            thisDateDayStringList = str.split(",");
        }

        // 按月查询
        if (thisMap.get(keyDateMonthString) != null){
            String str = null;
            if (thisMap.get(keyDateMonthString) instanceof String){
                str = (String) thisMap.get(keyDateMonthString);
            }else {
                str = ((String[]) thisMap.get(keyDateMonthString))[0];
            }
            String[] splitList = str.split(",");
            if (splitList != null && splitList.length > 0){
                thisDateMonthStringList = new String[splitList.length];
                for (int i = 0;i < splitList.length;i++){
                    thisDateMonthStringList[i] = camelToUnderline(splitList[i]);
                }
            }

        }

        // 按年查询
        if (thisMap.get(keyDateYearString) != null){
            String str = null;
            if (thisMap.get(keyDateYearString) instanceof String){
                str = (String) thisMap.get(keyDateYearString);
            }else {
                str = ((String[]) thisMap.get(keyDateYearString))[0];
            }
            thisDateYearStringList = str.split(",");
        }



        if (object != null){
            findMapColumnAndTableColumnList(object);
            //设置默认查询
            orderByDesc("create_time");
            dealQueryModel(object);

        }

    }

    public void setSelectColumn(String column){
        queryModel.setSelectColumn(column);
    }

    public QueryModel getQueryModel() {
        return queryModel;
    }

    public Integer getPageIndex() {
        return pageIndex;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void orderByDesc(String name){
        queryModel.setOrderByASC(null);
        queryModel.setOrderByDesc(camelToSuperline(name));

    }

    public void orderBy(String name){
        queryModel.setOrderByDesc(null);
        queryModel.setOrderByASC(camelToSuperline(name));
    }

    /**
     * 支持骆驼峰发，和 下划线 字段
     * @param groupBy
     */
    public void groupBy(String groupBy){
        queryModel.setGroupBy(camelToSuperline(groupBy));
    }
    public void eq(String table,String tableColumn, Object value){
        QueryItem queryItem = new QueryItem();
        queryItem.setType("eq");
        if (table != null && table.length() > 0){
            queryItem.setTableColumn(table+"."+tableColumn);
        }else {
            queryItem.setTableColumn(tableColumn);
        }
        queryItem.setValue(value);
        queryModel.getTableColumnValue().add(queryItem);
    }
    public void ge(String table,String tableColumn,Object value){
        QueryItem queryItem = new QueryItem();
        queryItem.setType("ge");
        if (table != null && table.length() > 0){
            queryItem.setTableColumn(table+"."+tableColumn);
        }else {
            queryItem.setTableColumn(tableColumn);
        }
        queryItem.setValue(value);
        queryModel.getTableColumnValue().add(queryItem);
    }

    public void le(String table,String tableColumn,Object value){
        QueryItem queryItem = new QueryItem();
        queryItem.setType("le");
        if (table != null && table.length() > 0){
            queryItem.setTableColumn(table+"."+tableColumn);
        }else {
            queryItem.setTableColumn(tableColumn);
        }
        queryItem.setValue(value);
        queryModel.getTableColumnValue().add(queryItem);
    }

    /**
     * 设置其他查询条件，需要以 And 或者 Or之类的开头
     * @param andWhereStr
     */
    public void whereOtherSql(String andWhereStr){
        queryModel.setAndWhereString(andWhereStr);
    }

    public void likeRight(String table,String tableColumn,Object value){
        QueryItem queryItem = new QueryItem();
        queryItem.setType("likeRight");
        if (table != null && table.length() > 0){
            queryItem.setTableColumn(table+"."+tableColumn);
        }else {
            queryItem.setTableColumn(tableColumn);
        }
        queryItem.setValue(value);
        queryModel.getTableColumnValue().add(queryItem);
    }

    //保存有效的数据库字段
    HashMap<String,List> mapTableColumn;


    //将 小写名称和Field 关联起来
    HashMap<String,Field> mapColumnField;

    //将 小写名称和Field 关联起来
    private HashMap<String,String> mapAsColumnSelect;

    //整理数据库字段
    private void findMapColumnAndTableColumnList(Object object){
        mapTableColumn = new HashMap<>();
        mapColumnField = new HashMap<>();
        mapAsColumnSelect = new HashMap<>();
        queryModel = new QueryModel();


        Class<?> aClass = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        Class<?> tClass = aClass;

        while (tClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
            fieldList.addAll(Arrays.asList(tClass.getDeclaredFields()));
            tClass = tClass.getSuperclass(); //得到父类,然后赋给自己
        }

        TableName tableName = aClass.getAnnotation(TableName.class);
        if (tableName == null){
            throw new RuntimeException("无法找到表名！");
        }
        queryModel.setTableName(tableName.value());
        try {
            for (int i = 0;i < fieldList.size();i++){
                Field field = fieldList.get(i);
                if (Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                field.setAccessible(true);
                TableField tableField = field.getAnnotation(TableField.class);

                String tableFieldName = "";
                if (tableField != null && tableField.value() != null && tableField.value().trim().length() > 0){
                    tableFieldName = tableField.value();
                }else {
                    tableFieldName = camelToUnderline(field.getName());
                }
                if (mapColumnField.get(tableFieldName) != null){
                    continue;
                }
                mapColumnField.put(tableFieldName,field);

                //转大写
                String asColunm = camelToSuperline(tableFieldName);
                //字段查询最终转大写返回
                String columnStr = queryModel.getTableName()+"."+tableFieldName+" as "+ asColunm;

                //model 直接关联数据库表, 需要使用的字段
                if (tableField != null && tableField.exist() != false){
                    //转大写
                    mapAsColumnSelect.put(asColunm,columnStr);
                    List list = new ArrayList();
                    list.add(asColunm);
                    list.add(queryModel.getTableName());
                    mapTableColumn.put(tableFieldName,list);
                }else if (tableField == null){
                    //转大写
                    mapAsColumnSelect.put(asColunm,columnStr);

                    List list = new ArrayList();
                    list.add(asColunm);
                    list.add(queryModel.getTableName());
                    mapTableColumn.put(tableFieldName,list);
                }

                //实现left join 语法，支持查询的字段
                LeftJoin leftJoin = field.getAnnotation(LeftJoin.class);
                if (leftJoin != null){
                    if (leftJoin.selectColumn() != null && leftJoin.selectColumn().length() > 0){
                        //获取关联查询表需要查询的字段
                        String[] allColumn = leftJoin.selectColumn().split(",");
                        for (String str:allColumn) {
                            String[] strList = str.split(" as ");
                            String str1 = strList[0].replace(" ","");
                            String str2 = "";
                            if (strList.length > 1){
                                str2 = strList[1].replace(" ","");
                            }else {
                                str2 = camelToSuperline(str1);
                            }

                            if (strList.length > 1){
                                Field field1 = mapColumnField.get(str2);
                                if (field1 != null){
                                    mapColumnField.put(str1,field1);
                                }
                            }
                            mapAsColumnSelect.put(str2,leftJoin.leftTable()+"."+str1+" as "+str2);
                            List list = new ArrayList();
                            list.add(str2);
                            list.add(leftJoin.leftTable());
                            mapTableColumn.put(str1,list);
                        }
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    private void dealQueryModel(Object object){
        try {
           Set<String> selkey = mapAsColumnSelect.keySet();
            for (String key: selkey) {
                //默认字段查询，model 涉及的 所有字段，最终转大写返回
                String selectStr = mapAsColumnSelect.get(key);
                if (queryModel.getDefaultColumn() != null){
                    selectStr = queryModel.getDefaultColumn()+" , "+selectStr;
                }
                queryModel.setDefaultColumn(selectStr);
            }

            Set<String> tableColumnList = mapTableColumn.keySet();
            for (String tableFieldName:tableColumnList ) {
                List<String> columnInfo = mapTableColumn.get(tableFieldName);

                Field field = mapColumnField.get(tableFieldName);
                if (field == null){
                    continue;
                }
                field.setAccessible(true);

                //实现left join 语法
                LeftJoin leftJoin = field.getAnnotation(LeftJoin.class);
                if (leftJoin != null){
                    String leftJoinStr = getLeftJoinString(leftJoin.leftTable(),leftJoin.leftTableColumn(),queryModel.getTableName()+"."+tableFieldName);
                    queryModel.getLeftJoinStr().add(leftJoinStr);
                }

                //处理查询条件
                //开始结束，默认实现区间条件
                String startStr = tableFieldName+keyStartFx;
                String endStr = tableFieldName+keyEndFx;
                Object startVal = thisMap.get(startStr);
                Object endVal = thisMap.get(endStr);

                String table = columnInfo.get(1);

                if (startVal != null || endVal != null){
                    String s = field.getType().getName();
                    if (s.endsWith(".Date")){
                        if (startVal != null){
                            if (startVal instanceof String){
                                startVal = toDataValueComplement((String) startVal);
                            }else {
                                String[] aa = (String[])startVal;
                                startVal = toDataValueComplement(aa[0]);
                            }
                        }
                        if (endVal != null){
                            if (endVal instanceof String){
                                endVal = toDataValueComplement((String) endVal);
                            }else {
                                String[] aa = (String[])endVal;
                                endVal = toDataValueComplement(aa[0]);
                            }
                        }
                    }
                    if (endVal == null){
                        ge(table,tableFieldName,startVal);
                    }else {
                        le(table,tableFieldName, endVal);
                    }
                }else {
                    Object valueObject = field.get(object);
                    if (valueObject == null || (valueObject instanceof String &&  valueObject.toString().length() == 0)){
                        continue;
                    }
                    String s = field.getType().getName();
                    if (s.endsWith(".Date")){
                        queryDateType(table,tableFieldName,valueObject);
                    }else if (valueObject instanceof String){
                        String thisStr = (String) valueObject;
                        boolean isLike = false;
                        if (thisLikeRightStringList != null && thisLikeRightStringList.length > 0){
                            for (int j = 0; j < thisLikeRightStringList.length; j++) {
                                if (thisLikeRightStringList[j].equals(tableFieldName)){
                                    isLike = true;
                                    break;
                                };
                            }
                        }
                        if (isLike){
                            // 判断是否模糊查询
                            likeRight(table,tableFieldName,thisStr);
                        }else {
                            eq(table,tableFieldName,thisStr);
                        };
                    }else {
                        eq(table,tableFieldName,valueObject);
                    }
                }
            }
            if (pageSize > 0 && pageIndex > 0){
                queryModel.setLimitStr( " limit "+  (pageSize)+" OFFSET "+ ((pageIndex-1)*pageSize) +" ");
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }





    /**
     * 查询日期精确度处理
     * @param tableFieldName
     * @param valueObject
     */
    private void  queryDateType(String table,String tableFieldName,Object valueObject){

        if (valueObject instanceof Date){
            valueObject = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,(Date) valueObject);
        }else if (valueObject instanceof String){
            valueObject = toDataValueComplement((String) valueObject);
        }else {
            String[] aa = (String[])valueObject;
            valueObject = toDataValueComplement(aa[0]);
        }
        String dataStr = (String) valueObject;

        int dateType = 0;

        // 按天查询
        if (dateType == 0){
            if (thisDateDayStringList != null && thisDateDayStringList.length > 0){
                for (int j = 0; j < thisDateDayStringList.length; j++) {
                    if (thisDateDayStringList[j].equals(tableFieldName)){
                        dateType = 3;
                        break;
                    };
                }
            }
        }

        //按年月查询
        if (dateType == 0){
            if (thisDateMonthStringList != null && thisDateMonthStringList.length > 0){
                for (int j = 0; j < thisDateMonthStringList.length; j++) {
                    if (thisDateMonthStringList[j].equals(tableFieldName)){
                        dateType = 2;
                        break;
                    };
                }
            }
        }

        //按年查询
        if (dateType == 0) {
            if (thisDateYearStringList != null && thisDateYearStringList.length > 0) {
                for (int j = 0; j < thisDateYearStringList.length; j++) {
                    if (thisDateYearStringList[j].equals(tableFieldName)) {
                        dateType = 1;
                        break;
                    };
                }
            }
        }

        //按小时查询
        if (dateType == 0) {
            if (thisDateHourStringList != null && thisDateHourStringList.length > 0) {
                for (int j = 0; j < thisDateHourStringList.length; j++) {
                    if (thisDateHourStringList[j].equals(tableFieldName)) {
                        dateType = 4;
                        break;
                    };
                }
            }
        }

        //按分钟查询
        if (dateType == 0) {
            if (thisDateMinuteStringList != null && thisDateMinuteStringList.length > 0) {
                for (int j = 0; j < thisDateMinuteStringList.length; j++) {
                    if (thisDateMinuteStringList[j].equals(tableFieldName)) {
                        dateType = 5;
                        break;
                    };
                }
            }
        }

        //根据时间长度查询相对应的日期
        if (dateType == 0){
            eq(null,tableFieldName,dataStr);
        }else if(dateType == 5){
            eq(null,"DATE_FORMAT("+table+"."+tableFieldName+",'%Y-%m-%d %H:%i')",dataStr.substring(0,16));
        }else if(dateType == 4){
            eq(null,"DATE_FORMAT("+table+"."+tableFieldName+",'%Y-%m-%d %H')",dataStr.substring(0,13));
        }else if(dateType == 3){
            eq(null,"DATE_FORMAT("+table+"."+tableFieldName+",'%Y-%m-%d')",dataStr.substring(0,10));
        }else if(dateType == 2){
            eq(null,"DATE_FORMAT("+table+"."+tableFieldName+",'%Y-%m')",dataStr.substring(0,7));
        }else if(dateType == 1){
            eq(null,"DATE_FORMAT("+table+"."+tableFieldName+",'%Y')",dataStr.substring(0,4));
        }
    }



    /**
     * 将驼峰命名转化成下划线
     * @param para
     * @return
     */
    public String camelToUnderline(String para){
        if(para.length()<3){
            return para.toLowerCase();
        }
        StringBuilder sb=new StringBuilder(para);
        int temp=0;//定位
        //从第三个字符开始 避免命名不规范
        for(int i=2;i<para.length();i++){
            if(Character.isUpperCase(para.charAt(i))){
                sb.insert(i+temp, "_");
                temp+=1;
            }
        }
        String str = sb.toString().toLowerCase();
        if (str.endsWith("[0]")){
            str.substring(0,str.length()-3);
        }
        return str;
    }

    /**
     * 将下划线转化成驼峰命名
     * @param para
     * @return
     */
    public String camelToSuperline(String para){
        if(para.length()<3){
            return para.toUpperCase();
        }
        String[] list = para.split("_");
        String str = list[0];
        for (int i = 1;i < list.length;i++){
            String strItem = list[i];
            str += strItem.substring(0,1).toUpperCase()+strItem.substring(1,strItem.length());
        }
        if(!str.startsWith("\"") || !str.endsWith("\"")){
            str = "\""+str+"\"";

        }
        return str;
    }


    /**
     * 补齐日期正确写法
     * @param para
     * @return
     */
    public Date toDataValueComplement(String para){
        String dayStr = DateUtils.dataStringValueComplement(para);
        return DateUtils.parseDate(dayStr);
    }

    private String getLeftJoinString(String leftTable,String leftColumnName,String thisColumnName){
        return " left join "+leftTable+" on "+leftTable+"."+leftColumnName+" = "+thisColumnName+"";
    }

    public static IPage getIPageNull(List list){
        return new IPage<JSONObject>() {
            @Override
            public List<OrderItem> orders() {
                return null;
            }

            @Override
            public List<JSONObject> getRecords() {
                return list;
            }

            @Override
            public IPage<JSONObject> setRecords(List<JSONObject> records) {
                return null;
            }

            @Override
            public long getTotal() {
                if (list == null){
                    return 0;
                }
                return  list.size();
            }

            @Override
            public IPage<JSONObject> setTotal(long total) {
                return null;
            }

            @Override
            public long getSize() {
                if (list == null){
                    return 0;
                }
                return list.size();
            }

            @Override
            public IPage<JSONObject> setSize(long size) {
                return null;
            }

            @Override
            public long getCurrent() {
                return 1;
            }

            @Override
            public IPage<JSONObject> setCurrent(long current) {
                return null;
            }
        };
    }

    public String getDefaultDateFormat() {
        return defaultDateFormat;
    }

    public void setDefaultDateFormat(String dateFormat){
        this.defaultDateFormat = dateFormat;
    }

    public Set<String> getAsColumnList() {
        if (mapAsColumnSelect != null){
            return mapAsColumnSelect.keySet();
        }
        return new Set<String>() {
            @Override
            public int size() {
                return 0;
            }

            @Override
            public boolean isEmpty() {
                return false;
            }

            @Override
            public boolean contains(Object o) {
                return false;
            }

            @Override
            public Iterator<String> iterator() {
                return null;
            }

            @Override
            public Object[] toArray() {
                return new Object[0];
            }

            @Override
            public <T> T[] toArray(T[] a) {
                return null;
            }

            @Override
            public boolean add(String s) {
                return false;
            }

            @Override
            public boolean remove(Object o) {
                return false;
            }

            @Override
            public boolean containsAll(Collection<?> c) {
                return false;
            }

            @Override
            public boolean addAll(Collection<? extends String> c) {
                return false;
            }

            @Override
            public boolean retainAll(Collection<?> c) {
                return false;
            }

            @Override
            public boolean removeAll(Collection<?> c) {
                return false;
            }

            @Override
            public void clear() {

            }
        };

    }
}
